package com.iamteer.day16;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import com.sun.javafx.geom.AreaOp.AddOp;

/**
泛型：JDK1.5 引入的新特性

泛型的好处：
	1. 将运行时的异常提前到了编译时
	2. 避免了无谓的强制类型转换
	
泛型在集合中的常见写法：
	ArrayList<String> list = new ArrayList<String>();
	//下面写法主要是考虑兼容性
	ArrayList<String> list = new ArrayList();
	ArrayList 		  list = new ArrayList<String>();
	
泛型没有多态，类型需要一致（一边泛型也可以，但不推荐）。

自定义泛型：一个数据类型的占位符或者是一个数据类型变量
	修饰符 <声明自定义的泛型>返回值类型 函数名(使用自定义泛型...){
	
	}

泛型中不能使用基本数据类型，要需要对应的对应的包装类
byte	---->	Byte
short	---->	Short
int		---->	Integer
long	---->	Long
double	---->	Double
float	---->	Float
boolean	---->	Boolean
char	---->	Character
	
泛型注意事项：
	1. 在方法上自定义泛型，这个自定义泛型的具体数据类型是在调用该方法的时候传入实参时确定具体的数据类型的。
	2. 自定义泛型只要符合标识符的命名规则即可，但一般习惯上使用一个大写字母表示，如：T（Type）和 E（Element）
	

------------------------------------------------------------------------------------------------------	
泛型类：

	class 类型<声明自定义泛型>{
	
	}
	注意事项：
		1. 在自定义泛型类的具体数据类型是在创建该类对象的时候确定的。
		2. 如果一个类声明了自定义泛型，但创建该类对象时没有指定具体数据类型，则默认为 Object 类型

------------------------------------------------------------------------------------------------------	
泛型接口：

	interface 接口名<声明自定义泛型>{
	
	}
	
	注意事项：
		1. 接口上自定义的泛型的具体数据类型是在实现一个接口的时候指定的。
		2. 在接口上自定义的泛型如果在实现接口的时候没有指定具体的数据类型，则默认为 Object 类型
		
	如果要延长接口自定义泛型的具体数据类型，格式如下：
	public class 类名<T> implements Dao<T>{
	
	}
	
------------------------------------------------------------------------------------------------------	
泛型的上下限：
	泛型中的通配符： ?
	
	泛型下限：
		? supper Integer: 只能传入 Integer 或者 Integer 的父类元素
		
	泛型上限：
		? extends Number: 只能传入 Number 或者 Number 的子类元素
		
 */

//class MyArrays<T>{	//可以使用泛型类，则类方法里就不需要再加上泛型了（静态方法仍需要自己声明）
class MyArrays{
	
	//元素翻转
	public static <T>void reverse(T[] arr){
		for (int startIndex = 0, endIndex = arr.length-1; startIndex<endIndex; startIndex++,endIndex--) {
			T temp = arr[startIndex];
			arr[startIndex] = arr[endIndex];
			arr[endIndex] = temp;
		}
	}
	
	//实现自己的 toString 方法
	public static <T>String toString(T[] arr) {
		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < arr.length; i++) {
			if (i == 0) {
				stringBuilder.append("[" + arr[i] + ", ");
			}else if (i == arr.length -1 ) {
				stringBuilder.append(arr[i] + "]");
			}else {
				stringBuilder.append(arr[i] + ", ");
			}
		}
		return stringBuilder.toString();
	}
}

interface Dao<T>{
	public void Add(T t);
}


public class Generics implements Dao<String>{

	public static void main(String[] args) {
		ArrayList<String> list = new  ArrayList<String>();
		list.add("110");
		list.add("abc");
		list.add("efg");
		list.add("test");
		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
			String string = (String) iterator.next();
			System.out.println(string.toUpperCase());
		}
		
		//用泛型实现传入什么类型返回什么类型
		String str = getDataT("abcde");
		int i =  getDataT(123);
		
//		int[] arr1 = {1, 2, 3, 4, 5, 6};	//不能使用基本类型，否则下面会报错
		Integer[] arr1 = {1, 2, 3, 4, 5, 6};
		MyArrays.reverse(arr1);
		System.out.println(MyArrays.toString(arr1));	
		
//		char arr2 = {'A', 'B', 'C', 'D', 'E', 'F'};	//不能使用基本类型，否则下面会报错
		Character[] arr2 = {'A', 'B', 'C', 'D', 'E', 'F'};
		MyArrays.reverse(arr2);
		System.out.println(MyArrays.toString(arr2));
		
		//泛型的下限：只能传入  Integer 或其父类
		ArrayList<Integer> list1 = new ArrayList<Integer>();
		ArrayList<Number> list2 = new ArrayList<Number>();
		ArrayList<Object> list3 = new ArrayList<Object>();
		ArrayList<String> list4 = new ArrayList<String>();
		
		print(list1);	//Integer 可以
		print(list2);	//Number 也可以
		print(list3);	//Object 也可以
//		print(list4);	//String 不可以（报错：Unresolved compilation problem）
		
		//泛型的上限：只能传入 Number 或其子类
		getData(list1);	//Integer 可以
		getData(list2);	//Number 也可以
//		getData(list3);	//Object 不可以（报错：Unresolved compilation problem）
//		getData(list4);	//String 不可以（报错：Unresolved compilation problem）
		
	}
	
	//用泛型实现传入什么类型返回什么类型
	public static <T>T getDataT(T o) {
		return o;
	}

	//演示泛型的下限：只能传入 Integer 或者其父类
	public static void print(Collection<? super Integer> c) {
		System.out.println(c);
	}
	
	//演示泛型的上限：只能传入 Number 或者其子类
	public static void getData(Collection<? extends Number> c) {
		System.out.println(c);
	}
	
	
	@Override
	public void Add(String t) {
		// TODO Auto-generated method stub
		System.out.println("Interface: Dao Method: Add");
	}
}
